//Agent.java
package controllers.Astar;

import java.util.ArrayList;
import core.game.Observation;
import core.game.StateObservation;
import core.player.AbstractPlayer;
import ontology.Types;
import tools.ElapsedCpuTimer;

public class Agent extends AbstractPlayer {
    protected ArrayList<Types.ACTIONS> path = new ArrayList<Types.ACTIONS>();
    protected ArrayList<Observation> grid[][];
    protected ArrayList<StateNode> frontier = new ArrayList<StateNode>();
    protected ArrayList<StateNode> explored = new ArrayList<StateNode>();
    protected StateNode startNode;
    protected int block_size;
    protected int flag;
    protected boolean found=false;

    public Agent(StateObservation so, ElapsedCpuTimer elapsedTimer)
    {
        grid = so.getObservationGrid();
        block_size = so.getBlockSize();
        startNode = new StateNode(so, null, null);
    }

    public StateNode getMinIndex() {
        if (frontier.size()==0) {
            return null;
        }
        else {
            double min = frontier.get(0).F;
            int ind = 0;
            for (int index=0; index<frontier.size(); index++) {
                if (frontier.get(index).F < min) {
                    ind = index;
                    min = frontier.get(index).F;
                }
            }
            StateNode temp = frontier.remove(ind);
            return temp;
        }
    }

    public void update(StateNode statenode) {
        for (int index=0; index < frontier.size(); index++) {
            if (frontier.get(index).state.equalPosition(statenode) && frontier.get(index).G > statenode.G) {
                frontier.remove(index);
                frontier.add(index, statenode);
                return;
            }
        }
        frontier.add(statenode);
        return;
    }

    public boolean checkExplored(StateNode statenode) {
        for (int index=0; index < explored.size(); index++) {
            if (explored.get(index).state.equalPosition((statenode.state))) {
                return true;
            }
        }
        return false;
    }

    public int Astar(StateNode statenode) {
        while(true) {
            explored.add(statenode);
            ArrayList<Types.ACTIONS> actions = statenode.state.getAvailableActions();
            for (int index=0; index<actions.size(); index++) {
                StateObservation stCopy = statenode.state.copy();
                stCopy.advance(actions.get(index));
                StateNode temp = new StateNode(stCopy, statenode, actions.get(index));
                update(temp);
            }
            StateNode temp = null;
            boolean condition = true;
            do {
                condition=true;
                temp = getMinIndex();
                if (temp==null) return -1;
                if (checkExplored(temp)) {
                    frontier.remove(temp);
                    condition=false;
                    continue;
                }
                if (temp.state.getGameWinner()==Types.WINNER.PLAYER_LOSES) {
                    frontier.remove(temp);
                    condition = false;
                    continue;
                }
                if (temp.state.getGameWinner()==Types.WINNER.PLAYER_WINS) {
                    StateNode a = temp;
                    while(a.lastAction!=null) {
                        path.add(0, a.lastAction);
                        a = a.fatherNode;
                    }
                    return 0;
                }
            } while(condition==false);
            statenode = temp;
        }
    }

    public Types.ACTIONS act(StateObservation stateObs, ElapsedCpuTimer elapsedTimer) {
        if (!found) {
            flag = Astar(startNode);
            found = true;
        }
        if (flag==-1) {
            System.out.print("No path.\n");
            return Types.ACTIONS.ACTION_NIL;
        }
        else {
            Types.ACTIONS action = path.remove(0);
            return action;
        }
    }
}
